package models

import (
	//"bytes"
	"context"
	//"encoding/json"
	"fmt"

	//"log"
	//"strconv"
	"strings"

	"time"
	//"io/ioutil"
	"myk8s/common"

	//"k8s.io/apimachinery/pkg/api/errors"

	"sigs.k8s.io/yaml"

	//"github.com/ghodss/yaml"

	appsv1 "k8s.io/api/apps/v1"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	//"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	//"k8s.io/apimachinery/pkg/api/resource"
	"k8s.io/apimachinery/pkg/runtime"

	//"k8s.io/apimachinery/pkg/api/resource"
	//yamlv2 "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
	//"k8s.io/apimachinery/pkg/util/intstr"
	//yamlutil "k8s.io/apimachinery/pkg/util/yaml"

	//"k8s.io/client-go/kubernetes/scheme"
	"github.com/tidwall/gjson"
	//"k8s.io/client-go/util/retry"

	//"k8s.io/apimachinery/pkg/runtime/serializer/json"
	// "k8s.io/client-go/kubernetes"
	//kubeAppV1 "k8s.io/client-go/kubernetes/typed/apps/v1"
	// "k8s.io/client-go/tools/clientcmd"
	//"k8s.io/klog/v2"
	//"k8s.io/client-go/dynamic"
	//"k8s.io/client-go/restmapper"

	"k8s.io/apimachinery/pkg/types"
)

type Deploy struct {
	DeployName string `json:"deployName" form:"deployName"`
	NameSpace  string `json:"nameSpace" form:"nameSpace"`
	//CreationTimestamp    time.Time `json:"created_time"`
	RevisionHistoryLimit int32  `json:"revisionHistoryLimit" form:"historyVersionLimit"`
	Replicas             int32  `json:"replicas" form:"replicas"`
	AvailableReplicas    int32  `json:"availableReplicas"`
	PodNumber            string `json:"podNumber"`
	Labels               string `json:"labels" form:"labels"`
	ContainerName        string `form:"containerName"`
	ImageUrl             string `json:"imageUrl" form:"imageUrl"`
	ContainerPortName    string `json:"-"form:"containerPortName"`
	ContainerPort        string `form:"containerPort"`
	HostPort             int32  `form:"hostPort"`
	// Resource             string    `json:"resource"`
	// StrategyType         string    `json:"strategyType"`
	CreateTime string `json:"createTime"` //创建时间
}

type DeployStatus struct {
	AvailableReplicas  string `json:"availableReplicas"`
	ObservedGeneration string `json:"observedGeneration"`
	ReadyReplicas      string `json:"readyReplicas"`
	Replicas           string `json:"replicas"`
	UpdatedReplicas    string `json:"updatedReplicas"`
	Conditions         []StatusConditions
}

type StatusConditions struct {
	LastTransitionTime string `json:"lastTransitionTime"`
	LastUpdateTime     string `json:"lastUpdateTime"`
	Message            string `json:"message"`
	Reason             string `json:"reason"`
	Status             string `json:"status"`
	Ctype              string `json:"ctype"`
}

type Replicaset struct {
	ReplicasetName string `json:"replicasetName"`
	ImageUrl       string `json:"imageUrl"`
	CreateTime     string `json:"createTime"`
}

// func ListDeploy(kubeconfig, namespace string) ([]appsv1.Deployment, error) {
func DeployList(kubeconfig, namespace, deployName string, labelsKey, labelsValue string) ([]Deploy, error) {

	//通过kubeconfig集群认证文件生成一个客户端操作对象clientset
	clientset := common.ClientSet(kubeconfig)

	//创建一个deployment资源的接口对象DeploymentClient，用于操作指定名称空间的deployment资源
	if namespace == "" {
		//namespace = corev1.NamespaceDefault
		namespace = corev1.NamespaceAll
	}
	DeploymentClient := clientset.AppsV1().Deployments(namespace)
	//调用接口对象DeploymentClient中的Get方法，获取相应的deployment资源数据	deploymentInstance,err:=DeploymentClient.Get(context.TODO(),deploymentName,metaV1.GetOptions{})

	//设置ListOptions
	var listOptions = metav1.ListOptions{}
	if labelsKey != "" && labelsValue != "" {
		listOptions = metav1.ListOptions{
			LabelSelector: fmt.Sprintf("%s=%s", labelsKey, labelsValue),
		}
	}

	// // 获取deployments
	// deployments, _ := clientset.AppsV1().Deployments("zx-app").List(listOptions)
	//var listOptions = metav1.ListOptions{}
	//if serviceName != "" {
	//	listOptions = metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%s", serviceName)}
	//}

	//deplist, err := DeploymentClient.List(context.TODO(), metav1.ListOptions{})
	deplist, err := DeploymentClient.List(context.TODO(), listOptions)
	// if err != nil {
	// 	klog.Errorf("list deployment error, err:%v", err)
	// 	return
	// }

	var bbb = make([]Deploy, 0)
	// jsonStr, err := json.Marshal(deplist.Items)
	// if err != nil {
	// 	fmt.Println("ERROR: simpledetail json.Marshal error")
	// }
	// fmt.Println(string(jsonStr))
	for _, dep := range deplist.Items {
		//搜索
		if deployName != "" {
			if !strings.Contains(dep.Name, deployName) {
				continue
			}
		}
		//用于判断是否有appanme标签，并根据标签记录对应的资源到应用下
		//var appName string

		var labelsStr, imgUrlStr, containerNameStr, ContainerPortNameStr, ContainerPortStr string
		for kk, vv := range dep.ObjectMeta.Labels {
			// if kk == "appname" {
			// 	appName = vv
			// }
			labelsStr += fmt.Sprintf("%s:%s,", kk, vv)
		}
		if len(labelsStr) > 0 {
			labelsStr = labelsStr[0 : len(labelsStr)-1]
		}

		for _, v2 := range dep.Spec.Template.Spec.Containers {
			containerNameStr += fmt.Sprintf("%s,", v2.Name)
			imgUrlStr += fmt.Sprintf("%s,", v2.Image)
			if len(v2.Ports) > 0 {
				ContainerPortNameStr += fmt.Sprintf("%s,", v2.Ports[0].Name)
				ContainerPortStr += fmt.Sprintf("%d,", v2.Ports[0].ContainerPort)
			}
		}
		if len(containerNameStr) > 0 {
			containerNameStr = containerNameStr[0 : len(containerNameStr)-1]
		}
		if len(imgUrlStr) > 0 {
			imgUrlStr = imgUrlStr[0 : len(imgUrlStr)-1]
		}
		if len(ContainerPortNameStr) > 0 {
			ContainerPortNameStr = ContainerPortNameStr[0 : len(ContainerPortNameStr)-1]
		}
		if len(ContainerPortStr) > 0 {
			ContainerPortStr = ContainerPortStr[0 : len(ContainerPortStr)-1]
		}
		//klog.Infof("deploy name:%s, replicas:%d, container image:%s", dep.Name, *dep.Spec.Replicas, dep.Spec.Template.Spec.Containers[0].Image)
		depItems := &Deploy{
			DeployName: dep.Name,
			NameSpace:  dep.Namespace,
			//CreationTimestamp:    dep.CreationTimestamp.Time,
			RevisionHistoryLimit: *dep.Spec.RevisionHistoryLimit,
			Replicas:             *dep.Spec.Replicas,
			AvailableReplicas:    dep.Status.AvailableReplicas,
			PodNumber:            fmt.Sprintf("%d/%d", dep.Status.AvailableReplicas, *dep.Spec.Replicas),
			Labels:               labelsStr,
			ContainerName:        containerNameStr,
			ImageUrl:             imgUrlStr,
			ContainerPortName:    ContainerPortNameStr,
			ContainerPort:        ContainerPortStr,
			//HostPort:             dep.Spec.Template.Spec.Containers[0].Ports[0].HostPort,
			// Resource:			dep.Spec.Template.Spec.Containers[0].Resources.Requests.Memory().
			// StrategyType:
			CreateTime: dep.CreationTimestamp.Format("2006-01-02 15:04:05"),
		}
		// if appName != "" {
		// 	jsonData, err := json.Marshal(&depItems)
		// 	if err == nil {
		// 		_ = common.HSet(appName, "deploy__"+dep.Name, string(jsonData))
		// 	}
		// }
		bbb = append(bbb, *depItems)
	}
	return bbb, err
}

//func DeployCreate(kubeconfig string, deployment *Deploy) error {
func DeployCreate(kubeconfig string, bodys []byte) error {

	gp := gjson.ParseBytes(bodys)

	clusterId := gp.Get("clusterId").String()
	if kubeconfig == "" {
		kubeconfig = clusterId
	}
	deployName := gp.Get("deployName").String()
	nameSpace := gp.Get("nameSpace").String()
	containerPort := gp.Get("containerPort").Int()
	replicas := gp.Get("replicas").Int()
	var pullPolicy corev1.PullPolicy
	imagePullPolicy := gp.Get("imagePullPolicy").String()
	switch imagePullPolicy {
	case "Never":
		pullPolicy = corev1.PullNever
	case "IfNotPresent":
		pullPolicy = corev1.PullIfNotPresent
	default:
		pullPolicy = corev1.PullAlways
	}
	imageUrl := gp.Get("imageUrl").String()

	//var labelsMap = make(map[string]string)
	labelsMap := map[string]string{
		"app": deployName,
	}
	for _, vv := range gp.Get("lables").Array() {
		labelsMap[vv.Get("key").String()] = vv.Get("value").String()
	}

	deployInstance := &appsv1.Deployment{
		TypeMeta: metav1.TypeMeta{
			Kind:       "Deployment",
			APIVersion: "apps/v1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:      deployName,
			Namespace: nameSpace,
			Labels:    labelsMap,
		},
		Spec: appsv1.DeploymentSpec{
			Replicas: int32Ptr(int32(replicas)),
			Selector: &metav1.LabelSelector{
				MatchLabels: labelsMap,
			},
			RevisionHistoryLimit: int32Ptr(10),
			Template: corev1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					//Name: "golang-pod",
					Labels: labelsMap,
				},
				Spec: corev1.PodSpec{
					Containers: []corev1.Container{
						corev1.Container{
							Name:            deployName,
							Image:           imageUrl,
							ImagePullPolicy: pullPolicy,
							Ports: []corev1.ContainerPort{
								corev1.ContainerPort{
									//Name:     ""     ,
									ContainerPort: int32(containerPort),
									//HostPort:      deployment.HostPort,
									Protocol: corev1.ProtocolTCP,
								},
							},
						},
					},
				},
			},
		},
	}

	DeployClient := common.ClientSet(kubeconfig).AppsV1().Deployments(nameSpace)
	//调用DeployClient接口中的create方法，创建deployment资源
	_, err := DeployClient.Create(context.TODO(), deployInstance, metav1.CreateOptions{})
	if err != nil {
		return err
	}
	return nil
}

func GetDeployYaml(kubeconfig, namespace, deploy string) (string, error) {

	DeploymentClient := common.ClientSet(kubeconfig).AppsV1().Deployments(namespace)
	deployment, err := DeploymentClient.Get(context.TODO(), deploy, metav1.GetOptions{})

	deploymentUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deployment)
	if err != nil {
		return "", err
	}
	yamlBytes, err := yaml.Marshal(deploymentUnstructured)
	if err != nil {
		return "", err
	}
	return string(yamlBytes), nil
}

//Restart
func DeployRestart(kubeconfig, namespace, deployName string) error {
	patchOpt := metav1.PatchOptions{FieldManager: "kubectl-rollout"}
	patchInfo := fmt.Sprintf(`{"spec":{"template":{"metadata":{"annotations":{"kubectl.kubernetes.io/restartedAt":"%s"}}}}}`, time.Now().Format(time.RFC3339))
	_, err := common.ClientSet(kubeconfig).AppsV1().Deployments(namespace).Patch(context.TODO(), deployName, types.StrategicMergePatchType, []byte(patchInfo), patchOpt)
	return err
}

func int32Ptr(i int32) *int32 { return &i }
